package com.glueball.crm.module.client.service;

import javax.ws.rs.Consumes;
import javax.ws.rs.GET;
import javax.ws.rs.POST;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.data.mongodb.core.query.Query;
import org.springframework.data.mongodb.core.query.Update;

import com.glueball.crm.module.client.model.BankAccount;
import com.glueball.crm.module.client.model.Client;
import com.glueball.crm.module.client.model.ClientType;
import com.glueball.crm.module.client.model.Company;
import com.glueball.crm.module.client.model.Contact;
import com.glueball.crm.module.client.model.CrmDate;
import com.glueball.crm.module.client.model.EmailAddress;
import com.glueball.crm.module.client.model.Person;
import com.glueball.crm.module.client.model.PersonName;
import com.glueball.crm.module.client.model.PhoneNumber;
import com.glueball.crm.module.util.KeyValue;
import com.mongodb.BasicDBObject;
import com.mongodb.CommandResult;

@Path("/client")
public class ClientService {
	
    @Autowired
    MongoTemplate mongoTemplate;
	
    @GET
    @Produces(MediaType.APPLICATION_JSON)
    @Path("getById/{id}")
	public Response getById(@PathParam(value = "id") final String id) {
    	Client client = (Client)this.mongoTemplate.findById(id, Client.class);
    	return Response.ok(client, MediaType.APPLICATION_JSON).build();
    }
	
    @POST
    @Consumes(MediaType.APPLICATION_JSON)
    @Produces(MediaType.APPLICATION_JSON)
    @Path("save")
	public Response addClient(final Client client) {
    	if (client.getId()==null) {
        	BasicDBObject obj = new BasicDBObject();
        	obj.append( "$eval", "getClientNumber()");
        	CommandResult result=mongoTemplate.executeCommand(obj);
        	String clientNumber = result.getString("retval");
        	client.setClientNumber(clientNumber);
    		this.mongoTemplate.insert(client);
    	} else {
    		this.mongoTemplate.save(client);
    	}
    	return Response.ok(client, MediaType.APPLICATION_JSON).build();
    }

    @POST
    @Consumes(MediaType.APPLICATION_JSON)
    @Produces(MediaType.APPLICATION_JSON)
    @Path("modify/{clientId}")
	public Response modifyClient(@PathParam(value="clientId") final String clientId,
			final KeyValue keyVal) {
    	this.mongoTemplate.updateFirst(new Query(Criteria.where("_id").is(clientId)),
    			new Update().set(keyVal.getKey(), keyVal.getValue()),
    			Client.class);
    	return Response.ok(keyVal, MediaType.APPLICATION_JSON).build();
    }

    @POST
    @Consumes(MediaType.APPLICATION_JSON)
    @Produces(MediaType.APPLICATION_JSON)
    @Path("data/modify/{clientId}")
	public Response modifyClientData(@PathParam(value="clientId") final String clientId,
			final KeyValue keyVal) {
    	this.mongoTemplate.updateFirst(new Query(Criteria.where("_id").is(clientId)),
    			new Update().set("data."+keyVal.getKey(), keyVal.getValue()),
    			Client.class);
    	return Response.ok(keyVal, MediaType.APPLICATION_JSON).build();
    }

    @POST
    @Consumes(MediaType.APPLICATION_JSON)
    @Produces(MediaType.APPLICATION_JSON)
    @Path("bankaccount/save/{clientId}")
	public Response saveBankAccount(@PathParam(value="clientId") final String clientId,
			final BankAccount account) {
    	if (account.getId()==null) {
	    	this.mongoTemplate.save(account);
	    	final Client client = (Client)this.mongoTemplate.findById(clientId, Client.class);
	    	client.getBankAccounts().add(account);
	    	this.mongoTemplate.save(client);
    	} else {
    		this.mongoTemplate.save(account);
    	}
    	return Response.ok(account, MediaType.APPLICATION_JSON).build();
    }
    
    @POST
    @Consumes(MediaType.APPLICATION_JSON)
    @Produces(MediaType.APPLICATION_JSON)
    @Path("contact/save/{clientId}")
	public Response saveContact(@PathParam(value="clientId") final String clientId,
			final Contact contact) {
    	if (contact.getId()==null) {
	    	this.mongoTemplate.save(contact);
	    	Client client = (Client)this.mongoTemplate.findById(clientId, Client.class);
	    	client.getContacts().add(contact);
	    	this.mongoTemplate.save(client);
    	} else {
    		this.mongoTemplate.save(contact);
    	}
    	return Response.ok(contact, MediaType.APPLICATION_JSON).build();
    }

    @POST
    @Consumes(MediaType.APPLICATION_JSON)
    @Produces(MediaType.APPLICATION_JSON)
    @Path("contact/phone/save/{contactId}")
	public Response savePhone(@PathParam(value="contactId") final String contactId,
			final PhoneNumber phone) {
    	if (phone.getId()==null) {
	    	this.mongoTemplate.save(phone);
	    	Contact contact = (Contact)this.mongoTemplate.findById(contactId, Contact.class);
	    	contact.getPhones().add(phone);
	    	this.mongoTemplate.save(contact);
    	} else {
    		this.mongoTemplate.save(phone);
    	}
    	return Response.ok(phone, MediaType.APPLICATION_JSON).build();
    }
    
    @POST
    @Consumes(MediaType.APPLICATION_JSON)
    @Produces(MediaType.APPLICATION_JSON)
    @Path("contact/email/save/{contactId}")
	public Response saveEmail(@PathParam(value="contactId") final String contactId, 
			final EmailAddress email) {
    	if (email.getId()==null) {
	    	this.mongoTemplate.save(email);
	    	Contact contact = (Contact)this.mongoTemplate.findById(contactId, Contact.class);
	    	contact.getEmails().add(email);
	    	this.mongoTemplate.save(contact);
    	} else {
    		this.mongoTemplate.save(email);
    	}
    	return Response.ok(email, MediaType.APPLICATION_JSON).build();
    }

    @POST
    @Consumes(MediaType.APPLICATION_JSON)
    @Produces(MediaType.APPLICATION_JSON)
    @Path("person/name/save/{clientId}")
	public Response savePersonName(@PathParam(value="clientId") final String clientId, 
			final PersonName name) {
    	final Client client = (Client)this.mongoTemplate.findById(clientId, Client.class);
    	if (client.getData()==null) {
    		client.setData(new Person());
    	} else if (!client.getType().equals(ClientType.PERSON.toString())) {
    		throw new IllegalArgumentException("This client is not a person");
    	}
    	((Person)client.getData()).setName(name);
    	this.mongoTemplate.save(client);

    	return Response.ok(name, MediaType.APPLICATION_JSON).build();
    }

    @POST
    @Consumes(MediaType.APPLICATION_JSON)
    @Produces(MediaType.APPLICATION_JSON)
    @Path("person/maidenname/save/{clientId}")
	public Response saveMaidenName(@PathParam(value="clientId") final String clientId, 
			final PersonName name) {
    	final Client client = (Client)this.mongoTemplate.findById(clientId, Client.class);
    	if (client.getData()==null) {
    		client.setData(new Person());
    	} else if (!client.getType().equals(ClientType.PERSON.toString())) {
    		throw new IllegalArgumentException("This client is not a person");
    	}
    	((Person)client.getData()).setMaidenName(name);
    	this.mongoTemplate.save(client);

    	return Response.ok(name, MediaType.APPLICATION_JSON).build();
    }

    @POST
    @Consumes(MediaType.APPLICATION_JSON)
    @Produces(MediaType.APPLICATION_JSON)
    @Path("person/mothersname/save/{clientId}")
	public Response saveMothersName(@PathParam(value="clientId") final String clientId, 
			final PersonName name) {
    	final Client client = (Client)this.mongoTemplate.findById(clientId, Client.class);
    	if (client.getData()==null) {
    		client.setData(new Person());
    	} else if (!client.getType().equals(ClientType.PERSON.toString())) {
    		throw new IllegalArgumentException("This client is not a person");
    	}
    	((Person)client.getData()).setMothersName(name);
    	this.mongoTemplate.save(client);

    	return Response.ok(name, MediaType.APPLICATION_JSON).build();
    }

    @POST
    @Consumes(MediaType.APPLICATION_JSON)
    @Produces(MediaType.APPLICATION_JSON)
    @Path("person/dateofbirth/save/{clientId}")
	public Response saveDateOfBirth(@PathParam(value="clientId") final String clientId, 
			final CrmDate dateOfBirth) {
    	final Client client = (Client)this.mongoTemplate.findById(clientId, Client.class);
    	if (client.getData()==null) {
    		client.setData(new Person());
    	} else if (!client.getType().equals(ClientType.PERSON.toString())) {
    		throw new IllegalArgumentException("This client is not a person");
    	}
    	((Person)client.getData()).setDateOfBirth(dateOfBirth);
    	this.mongoTemplate.save(client);

    	return Response.ok(dateOfBirth, MediaType.APPLICATION_JSON).build();
    }

    @POST
    @Consumes(MediaType.APPLICATION_JSON)
    @Produces(MediaType.APPLICATION_JSON)
    @Path("company/emailaddress/save/{clientId}")
	public Response saveCompanyEmailAddress(@PathParam(value="clientId") final String clientId, 
			final EmailAddress emailAddress) {
    	final Client client = (Client)this.mongoTemplate.findById(clientId, Client.class);
    	if (client.getData()==null) {
    		client.setData(new Company());
    	} else if (!client.getType().equals(ClientType.COMPANY.toString())) {
    		throw new IllegalArgumentException("This client is not a company");
    	}
    	((Company)client.getData()).setEmail(emailAddress);
    	this.mongoTemplate.save(client);

    	return Response.ok(emailAddress, MediaType.APPLICATION_JSON).build();
    }

    @POST
    @Consumes(MediaType.APPLICATION_JSON)
    @Produces(MediaType.APPLICATION_JSON)
    @Path("company/phonenumber/save/{clientId}")
	public Response saveCompanyPhoneNumber(@PathParam(value="clientId") final String clientId, 
			final PhoneNumber phoneNumber) {
    	final Client client = (Client)this.mongoTemplate.findById(clientId, Client.class);
    	if (client.getData()==null) {
    		client.setData(new Company());
    	} else if (!client.getType().equals(ClientType.COMPANY.toString())) {
    		throw new IllegalArgumentException("This client is not a company");
    	}
    	((Company)client.getData()).setPhone(phoneNumber);
    	this.mongoTemplate.save(client);

    	return Response.ok(phoneNumber, MediaType.APPLICATION_JSON).build();
    }
}
